#ifndef _GS_OBJECT_H_
#define _GS_OBJECT_H_
/*******************************************************************************
 ** Name: object.hpp                                                          **
 ** Description: WorldObject-derived container objects                        **
 **                                                                           **
 ** Open Source Initiative (OSI) Approved License                             **
 **                                                                           **
 ** The contents of this file are subject to the terms of the                 **
 ** Common Development and Distribution License, Version 1.0 only             **
 ** (the "License").  You may not use this file except in compliance          **
 ** with the License.                                                         **
 **                                                                           **
 ** You can find a copy of the license in the LICENSE file within             **
 ** this distribution or at $WIKI/display/GOVT/License-software.              **
 ** Software distributed under the License is distributed on an "AS IS"       **
 ** basis, WITHOUT WARRANTY OF ANY KIND, either express or implied.           **
 ** See the License for the specific language governing permissions           **
 ** and limitations under the License.                                        **
 **                                                                           **
 ** When distributing Covered Code, include this CDDL header in each          **
 ** file and include the License file at $GAME_DIR/LICENSE.                   **
 ** If applicable, add the following below this header, with the indicated    **
 ** fields enclosed by brackets "[]" replaced with your own identifying       **
 ** information: Portions Copyright [yyyy] [name of copyright owner]          **
 **                                                                           **
 ** Copyright (c) 2009-2011  Barry Gian James <gian@gamingods.net>            **
 ** All rights reserved.                                                      **
 ******************************************************************************/
// Modified $Date: 2012-08-14 20:47:30 -0600 (Tue, 14 Aug 2012) $ by $Author: unknown $
// Portions copyright 2012 Open Design Strategies, LLC.
// All rights reserved.

#define _object_h_ID    "$Id: object.hpp 69068 2012-08-15 02:47:30Z unknown $"

#include <boost/flyweight.hpp>

#include <stdarg.h>
#include <string>
#include <map>
#include <vector>
#include "common.hpp"
#include "cmd.hpp"
#include "visitor.hpp"
#include "uuid.hpp"

#define OBJECT_UNKNOWN     "<unknown>"
#define OBJECT_MAX_STACK	100

// TODO This needs to be replaced with something more manageable
enum class OType
{
    Unknown, Character, NPC, Door, Container, RangedWeapon, MeleeWeapon, 
    Item, Misc, Spell, Herb, Poltice, Potion, Area, Setting, Kit, Ammo,
    Agency, Weapon, Trash, Room, Scratch, Client, Trap, Electronic, Computer,
    Craftable,
    max
};

enum class ObjectType : ushort
{
	Item, Container, Weapon, Device, PC, NPC
};

enum class TierGrade : ushort
{
	Undefined, I, II, III, IV, V, VI, VII, VIII, IX, X
};

enum class LocationType : ushort
{
	Room, Character, Container, Inventory
};

//class Character;
//! @class WorldObject
//! @brief The base class for all instantiated objects in the world
#pragma db polymorphic pointer (boost::shared_ptr)
class WorldObject
{
public:
	SMART_PTR_DECL(WorldObject);

    //constructor and destructor
    WorldObject();
    WorldObject(OType t,std::string n);
    virtual ~WorldObject();


    // Getters
    const entity_t   ID() const { return _id; }
    const std::string	&	Name() const { return _name; }
    const std::string & Desc()  const { return _desc; }
    const std::string & 	Terse() const { return _terse; }
    const ObjectType		Type() const { return _type; }
    const int     		Weight() const { return _weight; }
    const std::string &	Tag() const { return _tag; }
    const TierGrade		Tier() const { return _tier; }
    const entity_t 		Size() const { return _size; }
    const entity_t 		Location() const { return _loc; }
    const ushort		X() const { return _x; }
    const ushort		Y() const { return _y; }
    const LocationType	LocType() const { return _loctype; }
    unsigned int		Flags() { return _flags; }
    const std::string &	Attribute(const std::string & a) const { return _attr.find(a)->second; }
    const boost::uuids::uuid & UUID() const { return uuid_; }

   // Setters
    void			Name(const std::string & n) { _name = n; }
    void			Desc(const std::string & d) { _desc = d; }
    void			Terse(const std::string t) { _terse = t; }
    void			Type(const ObjectType & t) { _type = t; }
    void			Weight(const int & w) { _weight = w; }
    void			AddAdjective(const std::string &s) { _adj.push_back(s); }
    void			AddAttribute(const std::string &a,const std::string &v)
    				{_attr[a] = v; }
    void			Tag(const std::string & t) { _tag = t; }
    void			Tier(const TierGrade & t) { _tier = t; }
    void			SetFlag(int f) { BMSET(_flags,f); }

    void			ClearFlag(int f) { BMCLR(_flags,f); }
    void			ClearAllFlags() { _flags = 0; }

    bool			IsAdjective(const std::string &);
    bool			IsAKA(const std::string&);

//    void *			LocationObject();
    bool			IsPC() { return _type == ObjectType::PC; }
    bool			IsCharacter() { return (_type == ObjectType::PC || _type == ObjectType::NPC); }

    // Commands over the object
    void			AddCommand(std::string &c);	//!< add by command name
    void			AddCommand(entity_t id);		//!< add by command id
    bool			HasCommand(std::string &c);
    bool			RemoveCommand(std::string &c);

    // TODO revisit this mechanism
    // @Deprecated This isn't how we do commands these days. ~gian
    //virtual int		Command(std::string cmd, std::string player) { return 0; }
    virtual void		accept(Pattern::Visitor & v) { }

protected:
    std::string   _name;       //!< Object name
    std::string    _desc;       //!< Object description (full version)
    std::string		_terse;		//!< terse/brief/short version of description
    // FIXME this OType is old and busted. We need something more manageable
    OType           _otype;      //!< Object base type
    ObjectType		_type;
	#pragma db id auto
    entity_t          _id;         //!< Unique ID
    int             _weight;     //!< uuum...
    std::vector<std::string>       _aka;        //!< other names for this object
    std::string		_tag;		//!< easier reference than remembering oid
	boost::uuids::uuid 	uuid_;		//!< the UUID of this object
	std::vector<std::string> _adj;	//!< any adjectives applied to this object
	//! all world objects may have any number of arbitrary attributes added
	//! at runtime and this supports that notion.
	std::map<std::string,std::string> _attr;
	unsigned int		_flags;		//!< object flags
	TierGrade		_tier;		//! Accessibility tier
	ushort			_x;			//! inside room coordinates
	ushort			_y;			//! inside room coordinates
	entity_t		_size;		//! id from size in DB
	LocationType	_loctype;
	entity_t		_loc;
	ushort			_slots;
	unsigned int	_value;		// suggested value of item or base price

	// we use boost::flyweight to reduce memory use of redundant objects
	// may change this container to something else depending on runtime
	// performance of adding/removing commands dynamically and often
	std::map<std::string,boost::flyweight<Command> > _cmds;
};


// Utility functions for use by STL algorithms 'n such
bool operator < (const WorldObject & a, const WorldObject & b);
bool operator == (const WorldObject & a, const WorldObject & b);


#endif 	/* _GS_OBJECT_H_ */
